﻿function Format-TSMData {
    <#
        .SYNOPSIS
            Format data from TSM output
                    
        .DESCRIPTION
            The Format-TSMData function accepts input from TSM in list format and outputs objects
        
        .PARAMETER Data
            The output from DSMADMC.EXE in list format (-displaymode=list) with headers removed (-dataonly=yes)

        .PARAMETER DefaultDisplaySet
            Defines which properties are displayed by default

        .EXAMPLE
            Format-TSMData -Data $data -DefaultDisplaySet $defaultDisplay

        .NOTES
            Contributors:  David Seibel
            Last Revision Date: 09/08/2015
    #>
    [CmdletBinding()]
    Param(
        [Parameter(Position=0,Mandatory=$true)]
        $Data,

        [Parameter(Position=1)]
        $TypeDefinitions,

        [Parameter(Position=2)]
        $DefaultDisplaySet,

        [Parameter(Position=3)]
        $FriendlyNames
    )
    #Create the default property display set
    if ($DefaultDisplaySet -ne $null) {
        $defaultDisplayPropertySet = New-Object System.Management.Automation.PSPropertySet(‘DefaultDisplayPropertySet’,[string[]]$DefaultDisplaySet)
        $PSStandardMembers = [System.Management.Automation.PSMemberInfo[]]@($defaultDisplayPropertySet)
    }
    
    # For formatting in title case below
    $textInfo = (Get-Culture).TextInfo

    $objects = @()
    $temp = New-Object PSObject
    foreach ($line in $Data) {
        <#
            Each line of query is returned in the following format:
                                NODE_NAME: V-7010-1-10
                                  NODE_ID: 34
                            PLATFORM_NAME: WinNT
                              DOMAIN_NAME: CLIENT01
                
            So, each line is split on the first colon and placed into a custom object.
            When an empty line is returned, the end of the object has been reached, so a new one is created.
        #>
        if ($line.Trim() -ne "") {
            # Extract property name and value
            $propArr = ($line -split ':', 2).Trim()
            $propName = $propArr[0]
            $propVal = $propArr[1]

            # Cast to type if specified
            if ($TypeDefinitions.Keys -contains $propName) {  
                # Special case type casters              
				if ($TypeDefinitions[$propName] -eq [bool]) {
					if ($propVal -iin ("yes","true")) {
						$propVal = $true
						$propVal = $propVal -as $TypeDefinitions[$propName]
					} elseif ($propVal -iin ("no","false")) {
						$propVal = $false
						$propVal = $propVal -as $TypeDefinitions[$propName]
					} else {
						Write-Warning "$propName (value: $propVal) could not be formatted as a boolean!"
					}
				} else {
                    # Normal case type caster
					$propVal = $propVal -as $TypeDefinitions[$propName]
				}
            }

            if ($FriendlyNames.Keys -contains $propName) {
                $propName = $FriendlyNames[$propName]
            } elseif ($propName -like "* *") {
                # Assume this is not SQL output, try to format into nice names
                $propName = $textInfo.ToTitleCase($propName)
                $propName = $propName -replace "[^a-zA-Z0-9]", ""
            }

            if ($temp.$propName -eq $null) {
                $temp | Add-Member -MemberType NoteProperty -Name $propName -Value $propVal
            } else {
                Write-Warning "A duplicate property was found while trying to create property '$propName' with value '$propVal' (Full line: $line)"               
            }
        } else {
            if ($DefaultDisplaySet -ne $null) {
                $temp.PSObject.TypeNames.Insert(0,'User.Information')
                $temp | Add-Member MemberSet PSStandardMembers $PSStandardMembers
            }
            $objects += $temp
            $temp = New-Object PSObject
        }        
    }
    return $objects
}